/**
 * Copyright 2018 orivil.com. All rights reserved.
 * Use of this source code is governed by a MIT-style
 * license that can be found at https://mit-license.org.
 */

package admin

import (
	"golang.org/x/crypto/bcrypt"
	"github.com/jinzhu/gorm"
	"time"
	"errors"
	"gitee.com/tugoer/orivil/bundles/db"
)

var (
	ErrWrongUsername = errors.New("用户名错误")
	ErrWrongPassword = errors.New("密码错误")
	ErrNotAllowedLogin = errors.New("该账户已被禁止登陆")
	ErrAdminRegistered = errors.New("admin already registered")
)

type Admin struct {
	ID int
	Name string `gorm:"unique_index"`
	Password string
	Email string `gorm:"index"`
	//AllowedLogin bool // 允许登陆
	AllowedSign int `desc:"1-允许登录 2-禁止切换"` // 允许登陆
	//AllowedSwitch bool `gorm:"index"`// 允许切换到兄弟帐号
	AllowedSelect int `gorm:"index" desc:"1-允许切换 2-禁止切换"`// 允许切换到兄弟帐号
	Level int
	Parent int `gorm:"index"`
	CreatedAt *time.Time
}

func (a *Admin)IsSuper() bool {
	return a.Parent == 0
}

func (a *Admin)BeforeCreate(gdb *gorm.DB) error {
	err := gdb.Model(a).Where("name=?", a.Name).First(a).Error
	if err != nil && err == gorm.ErrRecordNotFound {
		return nil
	} else {
		return ErrAdminRegistered
	}
}

// 创建管理员，该动作只能在系统内部操作，如初始化系统时创建超级管理员，不可提供接口给客户端
func (a *Admin)Create() error {
	pass, err := bcrypt.GenerateFromPassword([]byte(a.Password), 0)
	if err != nil {
		return err
	}
	a.Password = string(pass)
	return db.Gorm.Create(a).Error
}

func AdminCreateChild(parent int, child *Admin) error {
	child.Parent = parent
	child.AllowedSign = 1
	child.AllowedSelect = 1
	pass, err := bcrypt.GenerateFromPassword([]byte(child.Password), 0)
	if err != nil {
		return err
	}
	child.Password = string(pass)
	return db.Gorm.Create(child).Error
}

func CountChildren(parent int) (total int) {
	db.Gorm.Model(&Admin{}).Where("parent=?", parent).Count(&total)
	return
}

func GetSibling(a *Admin, siblingID int) (*Admin, error) {
	if a.AllowedSelect == 1 {
		admin := &Admin{}
		err := db.Gorm.Where("id=? AND parent=? AND allowed_select=?", siblingID, a.Parent, 1).First(&admin).Error
		return admin, err
	} else {
		return nil, errors.New("当前帐号不被允许切换帐号")
	}
}

func GetSiblings(a *Admin) (as []*Admin) {
	if a.AllowedSelect == 1 {
		db.Gorm.Where("id <> ? AND parent=? AND allowed_select=?", a.ID, a.Parent, 1).Find(&as)
	}
	return
}

func GetChildren(parent, limit, offset int) (as []*Admin) {
	db.Gorm.Where("parent=?", parent).Limit(limit).Offset(offset).Find(&as)
	return
}

func AdminUpdatePassword(loginName, password string) error {
	pass, err := bcrypt.GenerateFromPassword([]byte(password), 0)
	if err != nil {
		return err
	}
	return db.Gorm.Model(Admin{}).Where("name=?", loginName).Update(map[string]string{
		"password": string(pass),
	}).Error
}

func DeleteChild(childID int, parent *Admin) error {
	return db.Gorm.Where("id=? AND parent=?", childID, parent.ID).Delete(&Admin{}).Error
}

func UpdateChild(child, parent *Admin) error {
	if child.Password != "" {
		pass, err := bcrypt.GenerateFromPassword([]byte(child.Password), 0)
		if err != nil {
			return err
		}
		child.Password = string(pass)
	}
	if child.Level > parent.Level {
		child.Level = parent.Level
	}
	child.CreatedAt = nil
	return db.Gorm.Model(&Admin{}).Where("id=? AND parent=?", child.ID, parent.ID).Updates(child).Error
}

// AdminLogin 登陆管理员,
// 密码错误返回 ErrWrongPassword
// 账号错误返回 ErrWrongUsername
// 禁止登陆返回 ErrNotAllowedLogin
// 其他返回未知错误
func AdminLogin(name, password string) (a *Admin, err error) {
	a = &Admin{}
	err = db.Gorm.Where("name=?", name).First(a).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, ErrWrongUsername
		} else {
			return nil, err
		}
	}
	if a.AllowedSign == 2 {
		return nil, ErrNotAllowedLogin
	}
	err = bcrypt.CompareHashAndPassword([]byte(a.Password), []byte(password))
	if err != nil {
		if err == bcrypt.ErrMismatchedHashAndPassword {
			return nil, ErrWrongPassword
		} else {
			return nil, err
		}
	}
	return a, nil
}